<?php

namespace app\controller\common;

use App\model\AppModel;
use support\Request;
use WeChatPay\Builder;
use WeChatPay\Crypto\AesGcm;
use WeChatPay\Crypto\Rsa;
use WeChatPay\Formatter;
use WeChatPay\Util\PemUtil;

class WxPayUtil
{
    public static function jsapi($openid,$app_id,$fee,$description,$out_trade_no,$notify_url,$attach=[]){
        $xcx = AppModel::where('app_id','=',$app_id)->find();
        // 商户号
        $merchantId = $xcx['wxpay_mchid'];
        $appId = $xcx['xcx_app_id'];
        // 从本地文件中加载「商户API私钥」，「商户API私钥」会用来生成请求的签名
        $merchantPrivateKeyFilePath = 'file://'.public_path().'/wxCert/'.$merchantId.'/apiclient_key.pem';
        $merchantPrivateKeyInstance = Rsa::from($merchantPrivateKeyFilePath, Rsa::KEY_TYPE_PRIVATE);
        // 「商户API证书」的「证书序列号」
        $merchantCertificateSerial = $xcx['cert_serial'];
        // 从本地文件中加载「微信支付平台证书」，用来验证微信支付应答的签名
        $platformCertificateFilePath = 'file://'.public_path().'/wxCert/'.$xcx['platform_cert_serial'].'.pem';
        $platformPublicKeyInstance = Rsa::from($platformCertificateFilePath, Rsa::KEY_TYPE_PUBLIC);
        // 从「微信支付平台证书」中获取「证书序列号」
        $platformCertificateSerial = PemUtil::parseCertificateSerialNo($platformCertificateFilePath);
        // 构造一个 APIv3 客户端实例
        $instance = Builder::factory([
            'mchid'      => $merchantId,
            'serial'     => $merchantCertificateSerial,
            'privateKey' => $merchantPrivateKeyInstance,
            'certs'      => [
                $platformCertificateSerial => $platformPublicKeyInstance,
            ],
        ]);

        $params = [
            'appid'=>$appId,
            'mchid'=>$merchantId,
            'description'=>$xcx['short_name']."-".$description,
            'out_trade_no'=>$out_trade_no,
            'attach'=>json_encode($attach,true),
            'notify_url'=>config('app.host_name').$notify_url,
            'amount'=>[
                'total'=>round($fee*100),
                'currency'=>'CNY'
            ],
            'payer'=>[
                'openid'=>$openid
            ]
        ];
        try {
            $resp = $instance->chain('v3/pay/transactions/jsapi')->post([
                'json' => $params,
                'headers' => [
                    'Wechatpay-Serial' => $platformCertificateSerial,
                ]
            ]);
            $res = strval($resp->getBody());
            $res = json_decode($res,true);
            $timeStamp = time();
            $params=[
                'appId'=>$appId,
                'timeStamp'=>strval($timeStamp),
                'nonceStr'=>md5($timeStamp),
                'package'=>'prepay_id='.$res['prepay_id'],
            ];
            $params += ['paySign' => Rsa::sign(
                Formatter::joinedByLineFeed(...array_values($params)),
                $merchantPrivateKeyInstance
            ), 'signType' => 'RSA'];
            return success($params);
        } catch (\Exception $e) {
            $r = $e->getResponse();
            $r = json_decode(strval($r->getBody()),true);
            return error(1,$r['message']);
        }
    }
    public static function notifyDecrypt($request){
        $inHeader = $request->header();
        $inWechatpaySignature = $inHeader['wechatpay-signature'];
        $inWechatpayTimestamp = $inHeader['wechatpay-timestamp'];
        $inWechatpaySerial = $inHeader['wechatpay-serial'];
        $inWechatpayNonce = $inHeader['wechatpay-nonce'];
        $inBody = $request->rawBody();

        $xcx = AppModel::where('platform_cert_serial','=',$inWechatpaySerial)->find();

        $platformCertificateFilePath = 'file://'.public_path().'/wxCert/'.$inWechatpaySerial.'.pem';
        $platformPublicKeyInstance = Rsa::from($platformCertificateFilePath, Rsa::KEY_TYPE_PUBLIC);

        // 检查通知时间偏移量，允许5分钟之内的偏移
        $timeOffsetStatus = 300 >= abs(Formatter::timestamp() - (int)$inWechatpayTimestamp);
        $verifiedStatus = Rsa::verify(
            Formatter::joinedByLineFeed($inWechatpayTimestamp, $inWechatpayNonce, $inBody),
            $inWechatpaySignature,
            $platformPublicKeyInstance
        );

        if ($timeOffsetStatus && $verifiedStatus) {
            // 转换通知的JSON文本消息为PHP Array数组
            $inBodyArray = (array)json_decode($inBody, true);
            // 使用PHP7的数据解构语法，从Array中解构并赋值变量
            ['resource' => [
                'ciphertext'      => $ciphertext,
                'nonce'           => $nonce,
                'associated_data' => $aad
            ]] = $inBodyArray;
            // 加密文本消息解密
            $inBodyResource = AesGcm::decrypt($ciphertext, $xcx['api_v3_key'], $nonce, $aad);
            // 把解密后的文本转换为PHP Array数组
            $inBodyResourceArray = (array)json_decode($inBodyResource, true);
            return $inBodyResourceArray;
        }
        else{
            return [];
        }
    }
}